package evan.zhang.flags;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.widget.Toast;
import com.google.android.maps.GeoPoint;

public class Flags {

	private final static String tag = "FlagsOnMap::Flags";
	private final static int defaultLatSpan = 50000000;
	private final static int defaultLonSpan = 50000000;
	private final static int limitLatSpan = 20000000;
	private final static int limitLonSpan = 20000000;
	private final static String defaultTitle = "How to find flags?";
	private final static String defaultSnippet = "* Browse: Tap flag icons  \n* Search: Click search button";
	private final static GeoPoint defaultPoint = new GeoPoint(40076820,113300130);
	
	
	public static class FlagInfoReturnedBySearch {
		private GeoPoint geoPoint;
		private String distDefault;
		private String cityDefault;
		private String distLocal;
		private String cityLocal;
		private int latSpan;
		private int lonSpan;
		private Drawable smallFlag;
		
		public FlagInfoReturnedBySearch(Resources res) {
			setDefault(res);
		}
		public void setDefault(Resources res) {
			//default is my hometown Datong, China
			this.geoPoint = Flags.defaultPoint;
			this.distDefault = Flags.defaultTitle;
			this.cityDefault = Flags.defaultSnippet;
			this.distLocal = "";
			this.cityLocal = "";
			this.latSpan = Flags.defaultLatSpan;
			this.lonSpan = Flags.defaultLonSpan;
			this.smallFlag = res.getDrawable(R.drawable.star);
		}
		
		public GeoPoint getGeoPoint() {
			return this.geoPoint;
		}
		public void setGeoPoint(GeoPoint p) {
			this.geoPoint = p;
		}
		public String getDistDefault() {
			return this.distDefault;
		}
		public void setDistDefault(String s) {
			this.distDefault = s;
		}
		public String getCityDefault() {
			return this.cityDefault;
		}
		public void setCityDefault(String s) {
			this.cityDefault = s;
		}
		public String getDistLocal() {
			return this.distLocal;
		}
		public void setDistLocal(String s) {
			this.distLocal = s;
		}
		public String getCityLocal() {
			return this.cityLocal;
		}
		public void setCityLocal(String s) {
			this.cityLocal = s;
		}
		public int getLatSpan() {
			return this.latSpan;
		}
		public void setLatSpan(int i) {
			this.latSpan = i;
		}
		public int getLonSpan() {
			return this.lonSpan;
		}
		public void setLonSpan(int i) {
			this.lonSpan = i;
		}		
		public Drawable getSmallFlag() {
			return this.smallFlag;
		}
		public void setSmallFlag(Drawable d) {
			this.smallFlag = d;
		}
	}
	
	//We will use Flags in other class like, Flags.flagInfo.geoPoint 
	private final  FlagInfoReturnedBySearch flagInfo;
	//here we use five Lists as five columns in DB 
    private final int numberOfItem;
    private final List<String> distsDefault;
    private final List<String> capitalsDefault;
    private final List<String> distsLocal;
    private final List<String> capitalsLocal;
    private final List<GeoPoint> geoPoints;
    private final int[] latsSpan;
    private final int[] lonsSpan;
    private final List<Drawable> tinyFlags;
//  private final static Flags sInstance = new Flags();
//  private boolean isLoaded = false;
//	public static Flags getInstance() {
//		return sInstance;
//	}
    private Resources res;
    private boolean isDataLoad;
		
	public Flags(Resources res) {
		this.res = res;
		this.flagInfo = new FlagInfoReturnedBySearch(res);
	    this.numberOfItem = 231;
	    this.distsDefault = new ArrayList<String>(this.numberOfItem);
	    this.capitalsDefault = new ArrayList<String>(this.numberOfItem);
	    this.distsLocal   = new ArrayList<String>(this.numberOfItem);
	    this.capitalsLocal   = new ArrayList<String>(this.numberOfItem);
	    this.geoPoints  = new ArrayList<GeoPoint>(this.numberOfItem);
	    this.latsSpan = new int[this.numberOfItem]; 
	    this.lonsSpan = new int[this.numberOfItem];
	    this.tinyFlags = new ArrayList<Drawable>(this.numberOfItem);
		
	}
	
	public FlagInfoReturnedBySearch getFlagInfo() {
		return this.flagInfo;
	}
	public int getNumberOfItem() {
		return this.numberOfItem;
	}
	public List<String> getDistsDefault() {
		return this.distsDefault;
	}
	public List<String> getCapitalsDefault() {
		return this.capitalsDefault;
	}
	public List<String> getDistsLocal() {
		return this.distsLocal;
	}
	public List<String> getCapitalsLocal() {
		return this.capitalsLocal;
	}
	public List<GeoPoint> getGeoPoints() {
		return this.geoPoints;
	}
	public int[] getLatsSpan() {
		return this.latsSpan;
	}
	public int[] getLonsSpan() {
		return this.lonsSpan;
	}
	public List<Drawable> getTinyFlags() {
		return this.tinyFlags;
	}

    public void loadData() throws IOException {
    	if (this.isDataLoad) {
    		return;
    	}
        //Read flag_english.txt into memory
        InputStream flagEnglish = res.openRawResource(R.raw.flag_english);
        BufferedReader readerEnglish = new BufferedReader (new InputStreamReader(flagEnglish));
        Log.d(tag,"Read flag_english.txt file into memory");

        	String line;	
        	GeoPoint tempPoint;
        	String[] temp;
        	String distTemp;
        	int resourceId;
			while ((line = readerEnglish.readLine()) != null) {
				Log.d(tag,"line = " + line);
				temp = line.split("\t");
				this.distsDefault.add(temp[0].trim());
				this.capitalsDefault.add(temp[1].trim());
				tempPoint = new GeoPoint((int)(Double.parseDouble(temp[2])*1E6),(int)(Double.parseDouble(temp[3])*1E6));
				this.geoPoints.add(tempPoint);
				
				//figure out the flags
				distTemp = temp[0].trim().toLowerCase().replace(' ', '_');
				//Log.d(tag, "distTemp = "+distTemp);
				resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+distTemp, null, null);
				this.tinyFlags.add(res.getDrawable(resourceId));
			} 
			readerEnglish.close();
		
        //get the selected language from the language select Activity, hard coded here
        String language = "chinese_s";
        
        //Based on the user selected language, load the related file into memory and at the same time add the overlay items
        int languageFileId = res.getIdentifier("evan.zhang.flags:raw/flag_"+language, null, null);
        InputStream flagLocal = res.openRawResource(languageFileId);
        BufferedReader readerLocal = new BufferedReader (new InputStreamReader(flagLocal));   
        Log.d(tag,"Read flag_"+language+".txt file into memory");

        	String line1;
        	String[] temp1;
			while ((line1 = readerLocal.readLine()) != null) {
				
				//create a overlay item
				Log.d(tag,"line1 = " + line1);
				temp1 = line1.split("\t");
				this.distsLocal.add(temp1[0].trim());
				this.capitalsLocal.add(temp1[1].trim());
			}
			readerLocal.close();
		
		//Read the flag_span.txt
		InputStream flagSpan = res.openRawResource(R.raw.flag_span);
        BufferedReader readerSpan = new BufferedReader (new InputStreamReader(flagSpan));
        Log.d(tag,"Read flag_span.txt file into memory");
        	String line2;
        	String[] temp2;
        	int i = 0;
			while ((line2 = readerSpan.readLine()) != null) {
				//create a overlay item
				Log.d(tag,"line2 = " + line2);
				temp2 = line2.split("\t");
				this.latsSpan[i] = Integer.parseInt(temp2[1].trim());
				this.lonsSpan[i] = Integer.parseInt(temp2[2].trim());
				i++;
			}
			readerLocal.close();
			
			this.isDataLoad = true;
    }//end of function
    
    private String queryPreProcess(String query) {
    	StringBuilder builder = new StringBuilder();
    	String[] words = query.split(" ");
    	for (int i=0; i<words.length; i++) {
    		builder.append(this.queryPreProcessHelper(words[i].trim()));
    		if (i<words.length-1) { builder.append(' '); }
    	}
    	return builder.toString();
    }
    
    private String queryPreProcessHelper(String word) {
    	if (word.length() == 0) {
            return word;
        } else {
        	if (word.equals("and") || word.equals("of") || word.equals("the")) {
        		return word;
        	} else {
        		return word.substring(0,1).toUpperCase() + word.substring(1).toLowerCase();        	
        	}
        }
    }
    public boolean findPlaceAndFillFlagInfo(String query,  Resources res) {
    	String preProcessedQuery = queryPreProcess(query);
    	Log.d(tag, "preProcessedQuery = "+preProcessedQuery);
    	if (searchMyDataAndFillFlagInfo(preProcessedQuery,res) || handleOtherInputAndFillFlagInfo(preProcessedQuery,res)) {
    		//Log.d(tag, this.flagInfo.distLocal + this.flagInfo.geoPoint.toString());
    		return true;
    	}
    	else {
    		//Toast.makeText(context, query+" is not found!", Toast.LENGTH_LONG).show();
    		//Log.d(tag, "no place found!");
    		return false;
    	}
    	
    }

    private boolean searchMyDataAndFillFlagInfo(String query, Resources res) {
    	
    	int index = this.distsDefault.indexOf(query);
    	if ( index != -1) {//find the dist
    		this.flagInfo.distDefault = query;
    		this.flagInfo.cityDefault = this.capitalsDefault.get(index);
    		this.flagInfo.distLocal = this.distsLocal.get(index);
    		this.flagInfo.cityLocal = this.capitalsLocal.get(index);
    		this.flagInfo.geoPoint = this.geoPoints.get(index);
    		if (this.latsSpan[index]<Flags.limitLatSpan) {
    			this.flagInfo.latSpan = Flags.limitLatSpan;
        		this.flagInfo.lonSpan = Flags.limitLonSpan;
    		} else {
    			this.flagInfo.latSpan = this.latsSpan[index];
        		this.flagInfo.lonSpan = this.lonsSpan[index];
    		}
    		
    		String countrySmall = "s_"+this.flagInfo.distDefault.toLowerCase().replace(' ', '_');
    		int resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+countrySmall, null, null);
    		if (resourceId != -1) {
    			this.flagInfo.smallFlag = res.getDrawable(resourceId);
    		} else {
    			this.flagInfo.smallFlag = res.getDrawable(R.drawable.star);
    		}
    		return true;
    	}
    	
    	index = this.distsLocal.indexOf(query);
    	if ( index != -1) {//find the dist
    		this.flagInfo.distDefault = this.distsDefault.get(index);
    		this.flagInfo.cityDefault = this.capitalsDefault.get(index);
    		this.flagInfo.distLocal = query;
    		this.flagInfo.cityLocal = this.capitalsLocal.get(index);
    		this.flagInfo.geoPoint = this.geoPoints.get(index);
    		if (this.latsSpan[index]<Flags.limitLatSpan) {
    			this.flagInfo.latSpan = Flags.limitLatSpan;
        		this.flagInfo.lonSpan = Flags.limitLonSpan;
    		} else {
    			this.flagInfo.latSpan = this.latsSpan[index];
        		this.flagInfo.lonSpan = this.lonsSpan[index];
    		}
    		String countrySmall = "s_"+this.flagInfo.distDefault.toLowerCase().replace(' ', '_');
    		int resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+countrySmall, null, null);
    		if (resourceId != -1) {
    			this.flagInfo.smallFlag = res.getDrawable(resourceId);
    		} else {
    			this.flagInfo.smallFlag = res.getDrawable(R.drawable.star);
    		}
    		return true;
    	}
    	
    	index = this.capitalsDefault.indexOf(query);
    	if ( index != -1) {//find the dist
    		this.flagInfo.distDefault = this.distsDefault.get(index);
    		this.flagInfo.cityDefault = query;
    		this.flagInfo.distLocal = this.distsLocal.get(index);
    		this.flagInfo.cityLocal = this.capitalsLocal.get(index);
    		this.flagInfo.geoPoint = this.geoPoints.get(index);
    		if (this.latsSpan[index]<Flags.limitLatSpan) {
    			this.flagInfo.latSpan = Flags.limitLatSpan;
        		this.flagInfo.lonSpan = Flags.limitLonSpan;
    		} else {
    			this.flagInfo.latSpan = this.latsSpan[index];
        		this.flagInfo.lonSpan = this.lonsSpan[index];
    		}
    		String countrySmall = "s_"+this.flagInfo.distDefault.toLowerCase().replace(' ', '_');
    		int resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+countrySmall, null, null);
    		if (resourceId != -1) {
    			this.flagInfo.smallFlag = res.getDrawable(resourceId);
    		} else {
    			this.flagInfo.smallFlag = res.getDrawable(R.drawable.star);
    		}
    		return true;
    	}
    	
    	index = this.capitalsLocal.indexOf(query);
    	if ( index != -1) {//find the dist
    		this.flagInfo.distDefault = this.distsDefault.get(index);
    		this.flagInfo.cityDefault = this.capitalsDefault.get(index);
    		this.flagInfo.distLocal = this.distsLocal.get(index);
    		this.flagInfo.cityLocal = query;
    		this.flagInfo.geoPoint = this.geoPoints.get(index);
    		if (this.latsSpan[index]<Flags.limitLatSpan) {
    			this.flagInfo.latSpan = Flags.limitLatSpan;
        		this.flagInfo.lonSpan = Flags.limitLonSpan;
    		} else {
    			this.flagInfo.latSpan = this.latsSpan[index];
        		this.flagInfo.lonSpan = this.lonsSpan[index];
    		}
    		String countrySmall = "s_"+this.flagInfo.distDefault.toLowerCase().replace(' ', '_');
    		int resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+countrySmall, null, null);
    		if (resourceId != -1) {
    			this.flagInfo.smallFlag = res.getDrawable(resourceId);
    		} else {
    			this.flagInfo.smallFlag = res.getDrawable(R.drawable.star);
    		}
    		return true;
    	}
    	
    	return false;
    }
   
    private boolean handleOtherInputAndFillFlagInfo(String query, Resources res) {

    	Log.d(tag,"handleOtherInputAndFillFlagInfo() got called.");
    	
    	//handle the special case 1: Diaoyu Dao
    	/*
    	if (query.equalsIgnoreCase("diaoyu") || query.equalsIgnoreCase("diaoyudao") || query.equalsIgnoreCase("diaoyu dao") ||
    			query.equalsIgnoreCase("diao yu") || query.equalsIgnoreCase("diao yu dao") || query.equalsIgnoreCase("diaoyu islands") ||
    			query.equalsIgnoreCase("diaoyu island") || query.equals("钓鱼岛")||query.equals("钓鱼")) {
    	*/
    	if (query.contains("Diaoyu") || query.contains("Diao Yu") || query.contains("钓鱼")) {
    		this.flagInfo.distDefault = "China";
    		this.flagInfo.cityDefault = "Diaoyu Islands";
    		this.flagInfo.distLocal = "中国";
    		this.flagInfo.cityLocal = "钓鱼岛";
    		this.flagInfo.geoPoint = new GeoPoint(25745168,123473969);
    		this.flagInfo.latSpan = Flags.limitLatSpan;
    		this.flagInfo.lonSpan = Flags.limitLonSpan;
    		this.flagInfo.smallFlag = res.getDrawable(R.drawable.s_china);
    		return true;
    	}
    	
    	//handle the special case 2: People's republic of China (Google can not return this right)
    	if ((query.contains("People") && query.contains("Republic") && query.contains("China")) || 
    			query.contains("中华") && query.contains("人民")) {
    		this.searchMyDataAndFillFlagInfo("China", res);
    		return true;
    	}
    	//handle the special case 3: Myanmar (Burma)
    	if (query.contains("Burma")) {
    		this.searchMyDataAndFillFlagInfo("Myanmar",res);
    		this.flagInfo.distDefault = "Myanmar (Burma)";
    		return true;
    	}
    	
    	//handle the special case 4: Macedonia (FYROM)
    	if (query.contains("Macedonia (FYROM)")) {
    		this.searchMyDataAndFillFlagInfo("Macedonia",res);
    		return true;
    	}
    	/*
    	Geocoder coderChina = new Geocoder(context,Locale.CHINA);
    	List<Address> addressListChina = null;
    	try {
    		addressListChina = coderChina.getFromLocationName(query,1);
		} catch (IOException e) {
			Toast.makeText(context, "Network error, try it later!", Toast.LENGTH_LONG).show();
			return false;
		} finally {
			if (addressListChina == null || addressListChina.isEmpty() || addressListChina.get(0).getCountryName() == null || !addressListChina.get(0).hasLatitude() || !addressListChina.get(0).hasLongitude()) {
	    		Log.d(tag,"addressListChina is null or empty");
	    		return false;
	    	}
			Log.d(tag, "query = "+query);
			Log.d(tag, "addressListChina.toString() = "+addressListChina.toString());
		}
		*/
    	FlagsGeocoder myGeocoderC = new FlagsGeocoder("zh-CH");
    	if (!myGeocoderC.getResponseData(query)) return false;
    	
    	try {
			Thread.sleep(500);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
    	
		FlagsGeocoder myGeocoderE = new FlagsGeocoder("en");
		if (!myGeocoderE.getResponseData(query)) return false;
		
		//if it is a country
		if (myGeocoderE.isCountry()) {
    		//this.flagInfo.distLocal = addressListChina.get(0).getCountryName();
    		if (searchMyDataAndFillFlagInfo(myGeocoderE.getCountryName(),res)) {
    			return true;
    		}
    	}
    	
    	//this.flagInfo.geoPoint = new GeoPoint((int)(addressListChina.get(0).getLatitude()*1E6),(int)(addressListChina.get(0).getLongitude()*1E6));
    	this.flagInfo.geoPoint = myGeocoderC.getLocation();
		this.flagInfo.distLocal = "";
    	this.flagInfo.cityLocal = "";
    	this.flagInfo.distDefault = myGeocoderE.getFormattedAddress();
    	this.flagInfo.cityDefault = myGeocoderC.getFormattedAddress();
    //	if (myGeocoderC.hasBounds()) {
    //	   	this.flagInfo.latSpan = myGeocoderE.getBSpan()[0];
    //	   	this.flagInfo.lonSpan = myGeocoderE.getBSpan()[1];
    //	} else {
    	if (myGeocoderE.getVSpan()[0]<Flags.limitLatSpan) {
			this.flagInfo.latSpan = Flags.limitLatSpan;
    		this.flagInfo.lonSpan = Flags.limitLonSpan;
		} else {
			this.flagInfo.latSpan = myGeocoderE.getVSpan()[0];
    		this.flagInfo.lonSpan = myGeocoderE.getVSpan()[1];
		}
    //	}
    	String countrySmall = "s_"+myGeocoderE.getCountryName().toLowerCase().replace(' ', '_');
		//Log.d(tag, "countrySmall = s_"+this.tinyFlags.get(index));
		int resourceId = res.getIdentifier("evan.zhang.flags:drawable/"+countrySmall, null, null);
		if (resourceId != 0) {
			this.flagInfo.smallFlag = res.getDrawable(resourceId);
		} else {
			this.flagInfo.smallFlag = res.getDrawable(R.drawable.star);
		}
		
		return true;
    }
		
    
}//end of class